package com.simple.orm.agreement.process;

import com.simple.orm.agreement.annotation.Order;
import com.simple.orm.agreement.annotation.Protocol;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public abstract class AbstractWriteProcess<T> implements WriteProcess<T> {

    protected DataOutputStream dataOutputStream;

    protected DescribeEvent describeEvent;

    @Override
    public byte[] writeTo(T t) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        dataOutputStream = new DataOutputStream(byteArrayOutputStream);
        Class<?> aClass = t.getClass();
        Protocol protocol = aClass.getDeclaredAnnotation(Protocol.class);
        if (protocol == null) {
            throw new IllegalArgumentException(String.format("缺少注解：%s，无法获取协议的唯一标识", Protocol.class.getName()));
        }
        Field[] fields = aClass.getDeclaredFields();
        List<Field> list = new ArrayList<>();
        for (Field field : fields) {
            Order order = field.getDeclaredAnnotation(Order.class);
            if (order == null) {
                continue;
            }
            list.add(field);
        }
        list.sort((o1, o2) -> {
            Order order1 = o1.getDeclaredAnnotation(Order.class);
            Order order2 = o2.getDeclaredAnnotation(Order.class);
            return order1.value() - order2.value();
        });
        toProtocol(t, list); // 将目标对象转换成字节数组
        dataOutputStream.flush();
        byte[] data = byteArrayOutputStream.toByteArray(); // 复制原始字节数组
        byteArrayOutputStream.reset(); // 重置字节数组缓冲流，降低重复对象建立
        dataOutputStream.writeInt(data.length); // 写入原始数据的总大小
        dataOutputStream.write(data); // 向远程写入原始数据
        dataOutputStream.flush(); // 刷新缓冲流
        return byteArrayOutputStream.toByteArray(); // 返回可以发送的字节数组
    }

    /**
     * 获取已注册的描述事件处理器，默认为null
     *
     * @return 描述事件处理器
     */
    public DescribeEvent getDescribeEvent() {
        return describeEvent;
    }

    /**
     * 注册描述事件处理器
     *
     * @param describeEvent 描述事件处理器
     */
    public void setDescribeEvent(DescribeEvent describeEvent) {
        this.describeEvent = describeEvent;
    }

    /**
     * 通过分析实体对象，将其解析成输出流可以输出的对象，并且写入输出流
     *
     * @param t    要传递的对象
     * @param list 对象的字段集合
     */
    protected abstract void toProtocol(T t, List<Field> list);

    @Override
    public void close() throws IOException {
        if (dataOutputStream != null) dataOutputStream.close();
    }
}
